/*
 * Copyright (c) 2012 Sean Connelly
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

var assert = require('../assert.js').init();
var path = require('path');
var fs = require('fs');
var txs = require('../../src/js/text-stream.js');
var lxr = require('../../src/js/lex-rho.js');

function collapseTokens(str)
{
	var toks = lxr.lex(txs.create(str));
	var res = '';
	for (var i = 0; i < toks.length; i++)
		res += '[' + toks[i].toString() + ']';
	return res;
}

function loadRhoFile(test_dir, file)
{
	var c = fs.readFileSync(path.resolve(test_dir, file), 'utf8');
	assert.that(file + ' loaded', c.length > 0);
	return c;
}

exports.run = function(root_dir, test_dir, test_name) {

		assert.that('test1.rho lex\'ed correctly',
			collapseTokens(loadRhoFile(test_dir, 'test1.rho')) ===
			'[Version: rho:, v1.0]' +
			'[Ident: int]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[Ratio: 10, false]');

		assert.that('test2.rho lex\'ed correctly',
			collapseTokens(loadRhoFile(test_dir, 'test2.rho')) ===
			'[Version: rho:, v1.0]' +
			'[Keyword: define]' +
			'[Ident: test]' +
			'[Ident: class]' +
			'[Special: (]' +
			'[Special: )]' +
			'[Rhodent: my]' +
			'[Ident: int]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[Ratio: 12, false]' +
			'[Keyword: end]' +
			'[Ident: test]' +
			'[Ident: z]' +
			'[Ident: z]' +
			'[Special: .]' +
			'[Ident: x]' +
			'[Special: =]' +
			'[Ratio: 20, false]');

		assert.that('test3.rho lex\'ed correctly',
			collapseTokens(loadRhoFile(test_dir, 'test3.rho')) ===
			'[Version: rho:, v1.0]' +
			'[Ident: int]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[Ratio: 10, false]' +
			'[Special: +]' +
			'[Ratio: 20, false]' +
			'[Special: ^]' +
			'[Ratio: 2, false]');

		assert.that('test4.rho lex\'ed correctly',
			collapseTokens(loadRhoFile(test_dir, 'test4.rho')) ===
			'[Version: rho:, v1.0]' +
			'[Ident: say]' +
			'[Special: (]' +
			'[BeginText]' +
			'[Text: hello, world]' +
			'[EndText]' +
			'[Special: )]' +
			'[Ident: text]' +
			'[Ident: name]' +
			'[Special: :]' +
			'[BeginText]' +
			'[Text: Sean]' +
			'[EndText]' +
			'[Ident: say]' +
			'[Special: (]' +
			'[BeginText]' +
			'[Text: hi, name]' +
			'[EndText]' +
			'[Special: )]');

		assert.that('basic text',
			collapseTokens('rho:v1.0 text x: "This is a test"') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[Text: This is a test]' +
			'[EndText]');

		assert.that('empty text',
			collapseTokens('rho:v1.0 text x: ""') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[EndText]');

		assert.that('text interpolation',
			collapseTokens('rho:v1.0 text x: "one %{two} three"') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[Text: one ]' +
			'[BeginInnerExpr]' +
			'[Ident: two]' +
			'[EndInnerExpr]' +
			'[Text:  three]' +
			'[EndText]');

		assert.that('empty inner text',
			collapseTokens('rho:v1.0 text x: "one %{two + three}%{four} five"') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[Text: one ]' +
			'[BeginInnerExpr]' +
			'[Ident: two]' +
			'[Special: +]' +
			'[Ident: three]' +
			'[EndInnerExpr]' +
			'[BeginInnerExpr]' +
			'[Ident: four]' +
			'[EndInnerExpr]' +
			'[Text:  five]' +
			'[EndText]');

		assert.that('inner expression with object',
			collapseTokens('rho:v1.0 text x: "%{{a: 2}:a}"') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[BeginInnerExpr]' +
			'[Special: {]' +
			'[Ident: a]' +
			'[Special: :]' +
			'[Ratio: 2, false]' +
			'[Special: }]' +
			'[Special: :]' +
			'[Ident: a]' +
			'[EndInnerExpr]' +
			'[EndText]');

		assert.that('inner expression blob with escaping',
			collapseTokens("rho:v1.0 blob x: 'I have %{name}\\'s car'") ===
			'[Version: rho:, v1.0]' +
			'[Ident: blob]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginBlob]' +
			'[Blob: I have ]' +
			'[BeginInnerExpr]' +
			'[Ident: name]' +
			'[EndInnerExpr]' +
			'[Blob: \'s car]' +
			'[EndBlob]');

		assert.that('nested inner expressions',
			collapseTokens('rho:v1.0 text x: "1%{2~"3%{4}5"~6}7"') ===
			'[Version: rho:, v1.0]' +
			'[Ident: text]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[BeginText]' +
			'[Text: 1]' +
			'[BeginInnerExpr]' +
			'[Ratio: 2, false]' +
			'[Special: ~]' +
			'[BeginText]' +
			'[Text: 3]' +
			'[BeginInnerExpr]' +
			'[Ratio: 4, false]' +
			'[EndInnerExpr]' +
			'[Text: 5]' +
			'[EndText]' +
			'[Special: ~]' +
			'[Ratio: 6, false]' +
			'[EndInnerExpr]' +
			'[Text: 7]' +
			'[EndText]');

		assert.that('comment line with comment block',
			collapseTokens(loadRhoFile(test_dir, 'test5.rho')) ===
			'[Version: rho:, v1.0]' +
			'[Keyword: define]' +
			'[Ident: mynum]' +
			'[Ident: numcycle]' +
			'[Special: (]' +
			'[Ratio: 0, false]' +
			'[Special: ,]' +
			'[Special: (]' +
			'[Ratio: 3, false]' +
			'[Special: +]' +
			'[Ratio: 2, false]' +
			'[Special: )]' +
			'[Special: *]' +
			'[Ratio: 2, false]' +
			'[Special: )]' +
			'[Keyword: end]' +
			'[Ident: mynum]' +
			'[Ident: x]' +
			'[Special: :]' +
			'[Ratio: 15, false]' +
			'[Ident: say]' +
			'[Special: (]' +
			'[Ident: x]' +
			'[Special: )]' +
			'[CommentLine: ;(*]' +
			'[Keyword: if]' +
			'[Special: (]' +
			'[Ident: x]' +
			'[Special: )]' +
			'[Ident: int]' +
			'[Ident: x]' +
			'[Keyword: end]' +
			'[CommentLine: ;*)]');

		// MYTODO: add more tests, especially for lexing macros, and inside text literals with
		// string interpolation (i.e., "hello, %{name}")... and Rhotext!

		return assert.result();
	};
